package com.newtouch.bxzs.business.enclosure.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.newtouch.bxzs.business.enclosure.mapper.AttachmentMapper;
import com.newtouch.bxzs.business.enclosure.model.FileVO;
import com.newtouch.bxzs.business.enclosure.service.AttachmentService;
import com.newtouch.bxzs.common.base.BaseErrorEnum;
import com.newtouch.bxzs.common.base.BaseException;
import com.newtouch.bxzs.common.base.model.Attachment;
import com.newtouch.bxzs.common.base.model.vo.EnclosureVO;
import com.newtouch.bxzs.common.base.util.FileFormatUtil;
import com.newtouch.bxzs.common.base.util.UserDetailUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 附件相关操作service实现类
 *
 * <p>
 * <b>History:</b>
 * <table border="1">
 * <tr>
 * <th>Date</th>
 * <th>Operator</th>
 * <th>Memo</th>
 * </tr>
 * <tr>
 * <td>2020年12月31日</td>
 * <td>Amour</td>
 * <td>Create</td>
 * </tr>
 * </table>
 *
 * @author Amour
 * @version 1.0.0
 * @since 1.0.0
 */
@Service
public class AttachmentServiceImpl implements AttachmentService {

	/**
	 * 静态变量：系统日志
	 */
	private static final Log logger = LogFactory.getLog(AttachmentServiceImpl.class);

	@Value("${file.basePath}")
	private String fileBasePath;

	@Autowired
	AttachmentMapper attachmentMapper;

	/**
	 * 获取完成上传路径
	 *
	 * @param child
	 * @return
	 */
	private String getUploadPath(String child) {
		File upload = new File(fileBasePath, child);
		if (!upload.exists()) {
			upload.mkdirs();
		}
		return upload.getAbsolutePath();
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.newtouch.bxzs.common.base.service.AttachmentService#uploadFile(org.
	 * springframework.web.multipart.MultipartFile, java.lang.String)
	 */
	@Override
	public String uploadFile(MultipartFile file, String url, String type) {
		if (file.isEmpty()) {
			logger.error("上传附件失败，附件为空");
			throw new BaseException(BaseErrorEnum.FILE_UPLOAD_DEFULT);
		}
		/* 校验文件格式 */
		FileFormatUtil.fileFormatCheck(file);
		String fileName = file.getOriginalFilename();
		String filepath = this.getUploadPath(url);
		try (BufferedOutputStream out = new BufferedOutputStream(
				new FileOutputStream(new File(filepath + File.separator + fileName)))) {
			out.write(file.getBytes());
			out.flush();
			Attachment attachment = new Attachment("Amour", "Amour", fileName, url, type, url);
			attachmentMapper.insert(attachment);
			return fileName;
		} catch (FileNotFoundException e) {
			logger.error("上传附件失败！");
			return "上传附件失败！";
		} catch (IOException e) {
			logger.error("上传附件失败！");
			return "上传附件失败！";
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.newtouch.bxzs.enclosure.service.AttachmentService#uploadFile(java.
	 * util.List, java.util.List, java.lang.String, java.lang.String)
	 */
	@Override
	public List<String> uploadFile(List<MultipartFile> files, List<String> targetFileNames, String url, String type) {
		if (CollectionUtil.isEmpty(files) && CollectionUtil.isEmpty(targetFileNames)) {
			logger.error("上传附件失败，附件为空");
			throw new BaseException(BaseErrorEnum.FILE_UPLOAD_DEFULT);
		}
		/* 校验文件格式 */
		FileFormatUtil.filesFormatCheck(files);
		// 先查询本次url是否已经存在文件数据
		QueryWrapper<Attachment> query = new QueryWrapper<>();
		query.eq("ATTACHMENT_RELATION_ID", url);
		query.eq("ATTACHMENT_TYPE", type);
		List<Attachment> deleteAttachments = attachmentMapper.selectList(query);
		if (!CollectionUtil.isEmpty(deleteAttachments)) {
			List<String> deleteIds = new ArrayList<>();
			// 先删除不存在于targetFileNames的文件及数据
			for (Attachment attachment : deleteAttachments) {
				// 不存在于targetFileNames时,记录ID并删除文件
				if (CollectionUtil.isEmpty(targetFileNames)
						|| !targetFileNames.contains(attachment.getAttachmentName())) {
					deleteIds.add(attachment.getAttachmentId());
					String filePath = fileBasePath + File.separator + url + File.separator
							+ attachment.getAttachmentName();
					File deleteFile = new File(filePath);
					if (deleteFile.exists()) {
						deleteFile.delete();
					}
				}
			}
			// 删除附件表相关数据
			if (!deleteIds.isEmpty()) {
				attachmentMapper.deleteBatchIds(deleteIds);
			}
		}

		List<Attachment> attachments = new ArrayList<>();
		List<String> fileNames = new ArrayList<>();
		if (!CollectionUtil.isEmpty(files)) {
			for (MultipartFile file : files) {
				String fileName = file.getOriginalFilename();
				// TODO
				String filepath = this.getUploadPath(url);
				try (BufferedOutputStream out = new BufferedOutputStream(
						new FileOutputStream(new File(filepath + File.separator + fileName)))) {
					out.write(file.getBytes());
					out.flush();
					String userId = UserDetailUtil.getUserDetail().getUserId();
					Attachment attachment = new Attachment(userId, userId, fileName, url, type, url);
					// 此处直接在循环中进行insert操作，因为附件数量很少，使用批量插入反而增加冗余代码
					attachmentMapper.insert(attachment);
					attachments.add(attachment);
					fileNames.add(fileName);
				} catch (FileNotFoundException e) {
					logger.error("上传附件失败！");
					throw new BaseException(BaseErrorEnum.FILE_UPLOAD_DEFULT);
				} catch (IOException e) {
					logger.error("上传附件失败！");
					throw new BaseException(BaseErrorEnum.FILE_UPLOAD_DEFULT);
				}
			}
		}
		return fileNames;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.newtouch.bxzs.enclosure.service.AttachmentService#getEnclosureList(
	 * com.newtouch.bxzs.enclosure.model.EnclosureVO)
	 */
	@Override
	public HashMap<String, List<String>> getEnclosureList(EnclosureVO enclosureVO) {
		String relationId = enclosureVO.getAttachmentRelationId();
		if (StringUtils.isEmpty(relationId)) {
			throw new BaseException("-1", "关联ID不允许为空!");
		}
		QueryWrapper<Attachment> warpper = new QueryWrapper<>();
		warpper.eq("ATTACHMENT_RELATION_ID", relationId);
		if (!CollectionUtil.isEmpty(enclosureVO.getTypes())) {
			warpper.in("ATTACHMENT_TYPE", enclosureVO.getTypes());
		}
		List<Attachment> attachments = attachmentMapper.selectList(warpper);
		if (CollectionUtil.isEmpty(attachments)) {
			return null;
		}
		HashMap<String, List<String>> result = new HashMap<>();
		for (Attachment attachment : attachments) {
			List<String> urls = result.get(attachment.getAttachmentType());
			if (CollectionUtil.isEmpty(urls)) {
				urls = new ArrayList<>();
			}
			urls.add("/" + attachment.getAttachmentUrl() + "/" + attachment.getAttachmentName());
			result.put(attachment.getAttachmentType(), urls);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.newtouch.bxzs.enclosure.service.AttachmentService#downloadFile(java.
	 * lang.String)
	 */
	@Override
	public ResponseEntity<InputStreamResource> downloadFile(String url) throws IOException {
		FileSystemResource file = new FileSystemResource(fileBasePath + url);
		String fileName = file.getFilename();
		HttpHeaders headers = new HttpHeaders();
		headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
		headers.add("Content-Disposition",
				"attachment;filename=" + fileName + ";filename*=utf-8''" + URLEncoder.encode(fileName, "UTF-8"));
		headers.add("Pragma", "no-cache");
		headers.add("Expires", "0");
		return ResponseEntity.ok().headers(headers).contentLength(file.contentLength())
				.contentType(MediaType.parseMediaType("application/octet-stream"))
				.body(new InputStreamResource(file.getInputStream()));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.newtouch.bxzs.business.enclosure.service.AttachmentService#
	 * createFileUrl(com.newtouch.bxzs.business.enclosure.model.FileVO)
	 */
	@Override
	public String createFileUrl(FileVO fileVO) {
		String filePath = fileBasePath + File.separator + fileVO.getUrl() + File.separator + fileVO.getFileName();
		if (StringUtils.isEmpty(filePath) || filePath.length() <= 4) {
			throw new BaseException(BaseErrorEnum.REQUEST_DATA_NULL);
		}
		// 获取文件后缀，只允许预览pdf格式
		String endPath = filePath.substring(filePath.length() - 3, filePath.length());
		if (!"pdf".equals(endPath)) {
			throw new BaseException(BaseErrorEnum.FILE_TYPE_ERROR);
		}
		return filePath;
	}
}
